package com.woniu.common.utils.token;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.woniu.common.constant.UserConstants;
import com.woniu.common.enums.ExceptionCode;
import com.woniu.common.exception.CustomException;
import io.jsonwebtoken.*;
import org.apache.commons.codec.binary.Base64;

import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 杨光
 * @date 2021年08月12日 15:31
 */
public class JwtTokenUtils {
    private static String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCoAsaDbz2SmVxdYVAZ4uWpAKqt1XRSDgyD5giHUfQ1PbJpwvUzKvnIyoYoBs8r3G6jkRoV7Xa3PfKKu37BeHxZ+MPPFwX+9eUZQl+XeLDGOiV8Nq6PKN2AL/Aind8vuBBAI3kzKzwPrwClLVgTxut5zg6jpoWUSjYoWnupePgI7wIDAQAB";
    private static String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKgCxoNvPZKZXF1hUBni5akAqq3VdFIODIPmCIdR9DU9smnC9TMq+cjKhigGzyvcbqORGhXtdrc98oq7fsF4fFn4w88XBf715RlCX5d4sMY6JXw2ro8o3YAv8CKd3y+4EEAjeTMrPA+vAKUtWBPG63nODqOmhZRKNihae6l4+AjvAgMBAAECgYBcklrq5IoakmGwGgRWnwxHmFRyv5/97ju7GS4t0VwrUblSSNdtwAotNlnBCC9yTVywxyyGVHcK9BkFk9V9qHNrAl1mAT81a/eI3debbUzYtFXktUsyT42LN567AfElOM4G2bNSZXQg/1Buq/JDzxQz8go4ZwvuYpa/c7JUMiJgwQJBAN8cwbE3r1bTAgm5kD169I3Y7QahknXLJ9r8DVJ9+QMjflH8d8BjPVcuTwaTgmsSDgH6oMauUvdrdT0zkwC6HLECQQDAxr1TKo3fYR4zo9mRnU+PIPrsuuFCDX2LD3yN+hi0XO3GWwc2VrohIz3Nt7zWABuoBSJp13jNPzUW1O1yZWefAkAWRXqYRCS+mAWmDt31JSbwWe0fMlW6aHMsCukRiP2ocIyVhow1qjJfV4IP9/2WzpCTZf9Sleg2RoXHfDR6aBmhAkEAr3386lIJ93nE8cPOk8X+oFCovYte9y+qw0Zk4Cb2CHO0rec+SJRpOzOG1tjWWoacpreN3YafXVGWNeO/CW4RBwJAbJ451u2gOrTmiXZxidb1H7mdGmxNuOP4SgJBeQOWrqRnaMs72td9sSWTUoPCJGAKwg+0wbpPDzqxxwjFVtkYAw==";

    //生成jwttoken
    public static String generateJwtToken(Integer userId,String userName,String userAccount){
        AccToken accToken = new AccToken(userId, userName, userAccount);
        accToken.setExpireDateTime(new Date((new Date()).getTime()+3600*24*300*1000));//超时时间设置为半小时
        ObjectMapper mapper = new ObjectMapper();
        String ac = null;
        try {
            ac = mapper.writeValueAsString(accToken);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new CustomException(ExceptionCode.JSON_CONVERTION_EXCEPTION);
        }

        Map<String,Object> claims = new HashMap<>();
        claims.put(UserConstants.JWT_CLAIMS_KEY,ac);

        JwtBuilder builder = Jwts.builder();
        //使用对称加密生成jwt token
        builder.setClaims(claims).signWith(SignatureAlgorithm.HS512,UserConstants.JWT_SECRET_KEY);
        String jwtToken = builder.compact();

        return jwtToken;
    }

    //解析jwtToken
    public static AccToken parseToken(String jwtToken){
        AccToken accToken = null;
        try {
            JwtParser parser = Jwts.parser();
            //如果解析失败，会抛出异常
            Jws<Claims> claimsJws = parser.setSigningKey(UserConstants.JWT_SECRET_KEY).parseClaimsJws(jwtToken);
            Claims claims = claimsJws.getBody();
            String acJson = (String)claims.get(UserConstants.JWT_CLAIMS_KEY);
            ObjectMapper mapper = new ObjectMapper();
            accToken = mapper.readValue(acJson, AccToken.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return accToken;

    }



    //生成非对称加密的 jwttoken
    public static String generateWebJwtToken(Integer userId,String userName,String userAccount){
        AccToken accToken = new AccToken(userId, userName, userAccount);
        accToken.setExpireDateTime(new Date((new Date()).getTime()+3600*24*300*1000));//超时时间设置为半小时
        ObjectMapper mapper = new ObjectMapper();
        String ac = null;
        try {
            ac = mapper.writeValueAsString(accToken);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new CustomException(ExceptionCode.JSON_CONVERTION_EXCEPTION);
        }

        Map<String,Object> claims = new HashMap<>();
        claims.put(UserConstants.JWT_CLAIMS_KEY,ac);

        JwtBuilder builder = Jwts.builder();
        //使用RSA非对称加密生成token
        builder.setClaims(claims).signWith(SignatureAlgorithm.RS256, getRSAPrivateKey(privateKey));
        String jwtToken = builder.compact();

        return jwtToken;
    }

    //解析jwtToken（非对称加密RSA算法）
    public static AccToken parseWebToken(String jwtToken){
        AccToken accToken = null;
        try {
            JwtParser parser = Jwts.parser();
            //如果解析失败，会抛出异常
            Jws<Claims> claimsJws = parser.setSigningKey(getRSAPublicKey(publicKey)).parseClaimsJws(jwtToken);
            Claims claims = claimsJws.getBody();
            String acJson = (String)claims.get(UserConstants.JWT_CLAIMS_KEY);
            ObjectMapper mapper = new ObjectMapper();
            accToken = mapper.readValue(acJson, AccToken.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return accToken;

    }

    /**
     * 获取 RSAPrivateKey
     *
     * @param priKey base64加密私钥
     */
    private static RSAPrivateKey getRSAPrivateKey(String priKey)  {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(priKey));
        RSAPrivateKey privateKey = null;

        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            privateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return privateKey;
    }


    /**
     * 获取 RSAPublicKey
     *
     * @param pubKey base64加密公钥
     */
    private static RSAPublicKey getRSAPublicKey(String pubKey)  {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(pubKey));
        RSAPublicKey publicKey = null;

        try {
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return publicKey;
    }

    public static Map<String, String> genRsaKey() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(1024, new SecureRandom());
        KeyPair keyPair = keyPairGenerator.genKeyPair();
        byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
        byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
        System.out.println("=====================================================");
        System.out.println(Base64.encodeBase64String(publicKeyBytes));
        System.out.println("=====================================================");
        System.out.println(Base64.encodeBase64String(privateKeyBytes));
        System.out.println("=====================================================");
        HashMap<String, String> keyMap = new HashMap<>();
        keyMap.put("publicKey", Base64.encodeBase64String(publicKeyBytes));
        keyMap.put("privateKey", Base64.encodeBase64String(privateKeyBytes));
        return keyMap;
    }

    public static void main(String[] args) {
        String token = generateWebJwtToken(1, "admin", "admin");
        System.out.println(token);
        System.out.println("--------------");
        AccToken accToken = parseWebToken(token);
        System.out.println(accToken);
    }

}
